/**
  ETFRoot project, Anyang Normal University && IMP-CAS
  \class ETFAnaTask
  \brief abstract base class for tasks in the tracking stage
  \author SUN Yazhou, asia.rabbit@163.com
  \since 2021-10-04
  \date 2022-04-27 last modified
  \attention
  changelog
  <table>
  <tr>  <th>Date         <th>Author      <th>Description                   </tr>
  <tr>  <td>2021-10-04   <td>Asia Sun    <td>file created                  </tr>
  </table>

  \copyright Copyright (c) 2021 Anyang Normal U. && IMP-CAS with LGPLv3 LICENSE
*/

#include <regex>
#include <TClonesArray.h>
#include <TFolder.h>
#include <TH2F.h>
#include "ETFAnaTask.h"
#include "ETFDetectorManager.h"
#include "ETFTrackManager.h"
#include "ETFPIDManager.h"
#include "ETFParaManager.h"
#include "FairRootManager.h"
#include "ETFPID.h"
#include "ETFMsg.h"
#include "ETFPXISection.h"
#include "ETFPXIFragment.h"
#include "ETFVMEEvent.h"
#include "ETFVMERawEvent.h"
#include "ETFHPTDCChannel.h"
#include "ETFAmplitudeChannel.h"
#include "ETFOfflineSource.h"
#include "ETFVisual.h"

using std::regex;

ClassImp(ETFAnaTask);

ETFAnaTask::ETFAnaTask(const char *name, int verbose) : FairTask(name, verbose),
    fPXISection(0), fVMEEvent(0), fVMERawEvent(0), fPID(0), ffm(0), fpm(0), fdm(0),
    fVis(0), fFolder(0), hTimeToTrig(0){
  fDetDebug = false; fTrackingDebug = false; fPIDDebug = false;
  fIs3DTracking = false; fAnaLevel = 0;
  fParaM = ETFParaManager::Instance();
} // end ctor

ETFAnaTask::~ETFAnaTask(){
  if(fFolder){ delete fFolder; fFolder = nullptr; }
} // end dtor

void ETFAnaTask::Exec(Option_t *opt){
  if(fAnaLevel < 0) return; // only unpacking

  if(!fPXISection && !fVMEEvent && !fVMERawEvent)
  ETFMsg::Error("ETFAnaTask", "Exec: null member event pointer(s)");

  const int index = fPXISection->GetEventIndex();
  GetPID(); // assign fPID
  // assign the raw data to detetors --- ANALYSIS STAGE 1 //
  fdm->Reset(); // clear the last event
  fdm->SetBunchID(fPXISection->GetBunchID());
  fdm->SetEventIndex(index);
  if(fPXISection) for(TObject *tchObj : *fPXISection->GetHPTDCChannels()){
    ETFHPTDCChannel *tch = dynamic_cast<ETFHPTDCChannel *>(tchObj);
    if(!tch) ETFMsg::Error("ETFAnaTask", "Exec: null VME HPTDC channel encountered");
    const int chid = tch->GetChannelId();
    const int nl = tch->GetNofLeadingEdges(), nt = tch->GetNofTrailingEdges();
    fdm->Assign(tch);
    if(nl > 0 && nt > 0) hTimeToTrig->Fill(chid, tch->GetLeadingEdge(0));
  } // end if
  if(fVMEEvent && fVMERawEvent) for(TObject *tchObj : *fVMEEvent->GetHPTDCChannels()){
    ETFHPTDCChannel *tch = dynamic_cast<ETFHPTDCChannel *>(tchObj);
    if(!tch) ETFMsg::Error("ETFAnaTask", "Exec: null VME HPTDC channel encountered");
    const int chid = tch->GetChannelId();
    const int nl = tch->GetNofLeadingEdges(), nt = tch->GetNofTrailingEdges();
    fdm->Assign(tch);
    if(nl > 0 && nt > 0) hTimeToTrig->Fill(chid, tch->GetLeadingEdge(0));
  } // end if
  if(fDetDebug){ fdm->Print(); getchar(); }

  // do the tracking --- ANALYSIS STAGE 2 //
  if(fAnaLevel >= 1){
    ftm->Reset(); ftm->Map();
    // do the 3D tracking --- ANALYSIS STAGE * //
    if(fIs3DTracking) ftm->Map3D();
    if(fTrackingDebug){ ftm->Print(); getchar(); }
  } // end if
  // do the PID --- ANALYSIS STAGE 3 //
  if(fAnaLevel >= 2){
    fPID->Reset();
    // set the energy deposits and the pileup mark for fPID //
    fPID->SetdE0(fVMERawEvent->dE0()); fPID->SetdE1(fVMERawEvent->dE1());
    fPID->SetPileUp(fVMEEvent);
    // fly~~~
    fPID->Fly();
    if(fPIDDebug){ fPID->Print(); getchar(); }
  } // end if

  // draw the event --- ANALYSIS STAGE ** //
  if(fDrawVec.size()){
    if(find(fDrawVec.begin(), fDrawVec.end(), index) != fDrawVec.end())
      fVis->DrawEventSnap(index);
  } // end if
} // end member function Exec

InitStatus ETFAnaTask::Init(){
  ffm = FairRootManager::Instance();
  SourceType type = dynamic_cast<ETFOfflineSource *>(ffm->GetSource())->GetType();
  // decoded PXI data, stored in TClonesArray, section-fragment format reserved
  switch(type){
    case SourceType::kPXISOURCE: case SourceType::kMIXEDSOURCE:
      fPXISection = (ETFPXISection *)ffm->GetObject("PXISection");
      if(SourceType::kPXISOURCE == type) break;
    case SourceType::kVMESOURCE:
      /// decoded VME data, stored in TClonesArray
      fVMEEvent = (ETFVMEEvent *)ffm->GetObject("VMEEvent");
      /// primitive adc, qdc and scaler data
      fVMERawEvent = (ETFVMERawEvent *)ffm->GetObject("VMERawEvent");
      break;
    default:
      ETFMsg::Error("ETFAnaTask", "Init: Illigal source type");
      break;
  } // end switch

  fdm = ETFDetectorManager::Instance(); fdm->Configure();
  // fdm->SetDebug(fDebug);
  fpm = ETFPIDManager::Instance(); fVis = ETFVisual::Instance();
  Configure(); // configure the global managers - user customization
  if(fTrackingDebug) ftm->SetDebug();
  Register(); // register the mapped hits and recognized tracks
  CreateHistos(); // creat the histograms

  return kSUCCESS;
} // end member function Init

void ETFAnaTask::Configure(){
  ftm = ETFTrackManager::Instance(); // for specific user tracking requirements
} // end member function Configure

/// register the mapped data and recognized tracks in FairRootManager
void ETFAnaTask::Register(){
  fdm->Register();
  if(fAnaLevel >= 1) ftm->Register();
  if(fAnaLevel >= 2) fpm->Register();
} // end member function Register

void ETFAnaTask::FinishTask(){
  WriteHistos();
} // end member function FinishTask

void ETFAnaTask::CreateHistos(){
  fFolder = new TFolder("AnaTask", "Statistics for the Analysis Stage");
  hTimeToTrig = new TH2F("hTimeToTrig", "Time To Trigger v.s. Channel ID Distribution-1st \
Pulse-Overall;channelId;Tot", 10001, -0.5, 10000.5, 800, -500., 10000.);

  fFolder->Add(hTimeToTrig);
} // end member function CreateHistos

void ETFAnaTask::WriteHistos(){
  if(fFolder) fFolder->Write("", TObject::kOverwrite);
} // end member function WriteHistos


void ETFAnaTask::SetConfigFolder(const string &dir){
  // so that fConfigDir has a trailing '/' and no leading '/'
  fConfigDir = regex_replace(dir, regex("^/*([^/]*)/*"), "$1/");
} // end member function SetConfigFolder

void ETFAnaTask::SetChIdConfigFile(const string &file){
  fParaM->SetChIdConfigFile(fConfigDir+file);
} // end member function SetChIdConfigFile
void ETFAnaTask::SetDetPosConfigFile(const string &file){
  fParaM->SetDetPosConfigFile(fConfigDir+file);
} // end member function SetDetPosConfigFile
void ETFAnaTask::SetDelayConfigFile(const string &file){
  fParaM->SetDelayConfigFile(fConfigDir+file);
} // end member function SetDelayConfigFile
void ETFAnaTask::SetMisConfigFile(const string &file){
  fParaM->SetMisConfigFile(fConfigDir+file);
} // end member function SetMisConfigFile

ETFPID *ETFAnaTask::GetPID(){
  if(!fPID) fPID = ETFPIDManager::Instance()->GetPID();
  return fPID;
} // end member function GetPID

void ETFAnaTask::SetMagneticIntensity(double b){
  GetPID()->SetMagneticIntensity(b);
} // end member function SetMagneticIntensity
